import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { transports, format } from 'winston';
import chalk from 'chalk';
import * as path from 'path';
import { createClient } from 'redis';
import { ApolloDriver } from '@nestjs/apollo';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default';
import { AppController } from './app.controller';
import { App2Controller } from './app-v2.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { GraphQLModule } from '@nestjs/graphql';
import { MongoModule } from './modules/mongo/mongo.module';
import {
  AcceptLanguageResolver,
  CookieResolver,
  HeaderResolver,
  I18nModule,
  QueryResolver,
} from 'nestjs-i18n';
import { GetRequestParamsModule } from 'src/modules/get-request-params/get-request-params.module';
import { LifeCycleModule } from './modules/life-cycle/life-cycle.module';
import { AopModule } from './modules/aop/aop.module';
import { AllDecoratorModule } from './modules/all-decorator/all-decorator.module';
import { CustomDecoratorModule } from './modules/custom-decorator/custom-decorator.module';
import { ArgumentContextModule } from './modules/argument-context/argument-context.module';
import { DynamicModuleModule } from './modules/dynamic-module/dynamic-module.module';
import { LoggerModule } from './modules/logger/logger.module';
import { TypeOrmsModule } from './modules/typeorms/typeorms.module';
import { FlexibleDtoModule } from './modules/flexible-dto/flexible-dto.module';
import { EventEmittersModule } from './modules/event-emitters/event-emitters.module';
import { SseModule } from './modules/sse/sse.module';
import { PrismaModule } from './modules/prisma/prisma.module';
import { SocketModule } from './modules/socket/socket.module';
import { LifeCycleService } from './modules/life-cycle/life-cycle.service';
import { ArgumentContextService } from './modules/argument-context/argument-context.service';
import { LogMiddleware } from './middleware/log.middleware';
import { LoginGuard } from './guard/login.guard';
import { TimeInterceptor } from './interceptor/time.interceptor';
import { ValidatePipe } from './pipe/validate.pipe';
import { TestFilter } from './filter/test.filter';
import { User } from './entities/user.entity';
import { City } from './entities/city.entity';
import { StudentResolver } from './resolver/student.resolver';
import config from './config/config';

@Module({
  imports: [
    SocketModule,
    I18nModule.forRoot({
      fallbackLanguage: 'en',
      loaderOptions: {
        path: path.join(__dirname, '/i18n/'),
        watch: true,
      },
      resolvers: [
        new QueryResolver(['lang', 'l']),
        new HeaderResolver(['x-custom-lang']),
        new CookieResolver(['lang']),
        AcceptLanguageResolver,
      ],
    }),
    GraphQLModule.forRoot({
      driver: ApolloDriver,
      typePaths: ['./**/*.graphql'],
      playground: false,
      plugins: [ApolloServerPluginLandingPageLocalDefault()],
    }),
    MongoModule,
    MongooseModule.forRoot('mongodb://localhost:27017/huan'),
    PrismaModule,
    SseModule,
    EventEmitterModule.forRoot({
      wildcard: true,
      delimiter: '.',
    }),
    EventEmittersModule,
    FlexibleDtoModule,
    ConfigModule.forRoot({
      envFilePath: [path.join(process.cwd(), './config/env')],
      load: [config],
    }),
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: '',
      database: 'typeorm_test',
      synchronize: false,
      logging: false,
      entities: ['./entities/*.ts'],
      migrations: ['./migrations/*.ts'],
      poolSize: 10,
      connectorPackage: 'mysql2',
      extra: {
        authPlugin: 'sha256_password',
      },
    }),
    TypeOrmsModule,
    GetRequestParamsModule,
    LifeCycleModule,
    AopModule,
    AllDecoratorModule,
    CustomDecoratorModule,
    ArgumentContextModule,
    LoggerModule.forRoot({
      level: 'debug',
      transports: [
        new transports.Console({
          format: format.combine(
            format.colorize(),
            format.printf(({ context, level, message, time }) => {
              const appStr = chalk.green(`[NEST]`);
              const contextStr = chalk.yellow(`[${context}]`);

              return `${appStr} ${time} ${level} ${contextStr} ${message} `;
            }),
          ),
        }),
        new transports.File({
          format: format.combine(format.timestamp(), format.json()),
          filename: '111.log',
          dirname: 'log',
        }),
      ],
    }),
    DynamicModuleModule.register({
      aaa: 111,
      bbb: 222,
    }),
  ],
  // 多版本共存顺序按照从左到右执行
  controllers: [App2Controller, AppController],
  providers: [
    AppService,
    LifeCycleService,
    ArgumentContextService,
    {
      provide: 'app_service',
      useClass: AppService,
    },
    // {
    //   provide: APP_GUARD,
    //   useClass: LoginGuard
    // },
    // {
    //   provide: APP_INTERCEPTOR,
    //   useClass: TimeInterceptor
    // },
    // {
    //   provide: APP_PIPE,
    //   useClass: ValidatePipe
    // },
    // {
    //   provide: APP_FILTER,
    //   useClass: TestFilter
    // },
    {
      provide: 'person1',
      useValue: {
        name: 'aaa',
        age: 20,
      },
    },
    {
      provide: 'person2',
      useFactory() {
        return {
          name: 'bbb',
          age: 20,
        };
      },
    },
    {
      provide: 'person3',
      useFactory(person: { name: string }, appService: AppService) {
        return {
          name: person.name,
          desc: appService.test(),
        };
      },
      inject: ['person1', AppService],
    },
    {
      provide: 'person4',
      async useFactory() {
        await new Promise((resolve) => {
          setTimeout(resolve, 2000);
        });
        return {
          name: '张三',
          age: 18,
        };
      },
    },
    {
      provide: 'person5',
      useExisting: 'person4',
    },
    {
      provide: 'REDIS_CLIENT',
      async useFactory() {
        try {
          const client = createClient({
            socket: {
              host: 'localhost',
              port: 6379,
            },
          });
          await client.connect();
          return client;
        } catch (e) {
          return '连接 redis 失败';
        }
      },
    },
    StudentResolver,
  ],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LogMiddleware).forRoutes('*');
  }
}
